package com.q3d.demo.api.user.client.grpc;

import java.util.ArrayList;

import javax.validation.Valid;

import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import com.q3d.demo.api.user.grpc.UuidGrpc;
import com.q3d.demo.api.user.grpc.UuidListGrpc;
import com.q3d.demo.api.user.grpc.IdExtGrpc;
import com.q3d.demo.api.user.grpc.IdExtListGrpc;
import com.q3d.demo.api.user.grpc.CountResultGrpc;
import com.q3d.demo.api.user.grpc.UserBaseGrpcP1;
import com.q3d.demo.api.user.grpc.UserBaseGrpcP1K1;
import com.q3d.demo.api.user.grpc.UserBaseGrpcP1K2;
import com.q3d.demo.api.user.grpc.UserBaseGrpcP1List;
import com.q3d.demo.api.user.grpc.OpResultGrpc;
import com.q3d.demo.api.user.grpc.UserBaseGrpcR1K1;
import com.q3d.demo.api.user.grpc.UserBaseGrpcR1K1List;
import com.q3d.demo.api.user.grpc.UserBaseGrpcR1K2;
import com.q3d.demo.api.user.grpc.UserBaseGrpcR1K2List;
import com.q3d.demo.api.user.grpc.PageRequestGrpc;
import com.q3d.demo.api.user.grpc.StringGrpc;
import com.q3d.demo.api.user.grpc.UserBaseServiceGrpc.UserBaseServiceBlockingStub;
import com.q3d.demo.api.user.service.UserBaseServiceInterface;
import com.q3d.demo.common.lib.service.dto.CountResultDto;
import com.q3d.demo.common.lib.service.dto.IdExtDto;
import com.q3d.demo.common.lib.service.dto.IdExtListDto;
import com.q3d.demo.common.lib.service.dto.OpResultDto;
import com.q3d.demo.common.lib.service.dto.PageRequestDto;
import com.q3d.demo.common.lib.service.dto.StringDto;
import com.q3d.demo.common.lib.service.dto.UuidDto;
import com.q3d.demo.common.lib.service.dto.UuidListDto;
import com.q3d.demo.api.user.dto.UserBaseP1Dto;
import com.q3d.demo.api.user.dto.UserBaseP1K1Dto;
import com.q3d.demo.api.user.dto.UserBaseP1K2Dto;
import com.q3d.demo.api.user.dto.UserBaseP1ListDto;
import com.q3d.demo.api.user.dto.UserBaseR1K1Dto;
import com.q3d.demo.api.user.dto.UserBaseR1K1ListDto;
import com.q3d.demo.api.user.dto.UserBaseR1K2Dto;
import com.q3d.demo.api.user.dto.UserBaseR1K2ListDto;

import net.devh.boot.grpc.client.inject.GrpcClient;

@Service
@Validated /** Controller 中某些接口的入参可能没有封装 DTO 进行校验，因此在 Service 层再做一次校验 */
/**
 * 远程接口的具体实现：gRPC 调用
 * 
 * @author 叶湘 ( weixin:yexiang841, email:yexiang841@qq.com )
 */
public class UserBaseClientGrpc implements UserBaseServiceInterface {

        @GrpcClient("user-svc-v1") /** 声明一个 gRPC Stub 客户端，括号中是 Channel 名，也就是微服务名 */
        protected UserBaseServiceBlockingStub helloServiceStub;

        @Autowired
        protected ModelMapper modelMapper;

        @Override
        public StringDto hello(@Valid StringDto dtoStringRequest) {
                // gRPC 请求的参数使用 Builder 装配模式
                StringGrpc grpcStringRequest = StringGrpc.newBuilder()
                                .setText(dtoStringRequest.getText())
                                .build();
                // 此处是远程 gRPC 调用
                StringGrpc grpcStringResponse = helloServiceStub.hello(grpcStringRequest);
                StringDto dtoStringResponse = StringDto.builder().text(grpcStringResponse.getText()).build();
                return dtoStringResponse;
        }

        @Override
        public UuidDto addOne(UserBaseP1Dto dtoP1) {
                // 将 DTO 对象转换为 gRPC 对象
                UserBaseGrpcP1 grpcP1 = modelMapper.map(dtoP1, UserBaseGrpcP1.Builder.class).build();
                // 此处是远程 gRPC 调用
                UuidGrpc grpcUuid = helloServiceStub.addOne(grpcP1);
                UuidDto dtoUuid = UuidDto.builder().uuid(grpcUuid.getUuid()).build();
                return dtoUuid;
        }

        @Override
        public UuidListDto addBatch(@Valid UserBaseP1ListDto dtoP1List) {
                // gRPC 请求的参数使用 Builder 装配模式
                UserBaseGrpcP1List.Builder grpcP1ListBuilder = UserBaseGrpcP1List.newBuilder();
                for (UserBaseP1Dto dtoP1 : dtoP1List.getDtoList()) {
                        // 将 DTO 对象转换为 gRPC 对象
                        UserBaseGrpcP1 grpcP1 = modelMapper.map(dtoP1, UserBaseGrpcP1.Builder.class).build();
                        grpcP1ListBuilder.addGrpc(grpcP1);
                }
                UserBaseGrpcP1List grpcP1List = grpcP1ListBuilder.build();
                // 此处是远程 gRPC 调用
                UuidListGrpc grpcUuidList = helloServiceStub.addBatch(grpcP1List);
                UuidListDto dtoUuidList = UuidListDto.builder()
                                .dtoList(new ArrayList<UuidDto>(grpcP1List.getGrpcCount())).build();
                for (UuidGrpc grpcUuid : grpcUuidList.getGrpcList()) {
                        UuidDto dtoUuid = UuidDto.builder().uuid(grpcUuid.getUuid()).build();
                        dtoUuidList.getDtoList().add(dtoUuid);
                }
                return dtoUuidList;
        }

        @Override
        public OpResultDto removeOne(@Valid UuidDto dtoUuid) {
                // gRPC 请求的参数使用 Builder 装配模式
                UuidGrpc grpcUuid = UuidGrpc.newBuilder()
                                .setUuid(dtoUuid.getUuid())
                                .build();
                // 此处是远程 gRPC 调用
                OpResultGrpc grpcOpResult = helloServiceStub.removeOne(grpcUuid);
                OpResultDto dtoOpResult = OpResultDto.builder().opResult(grpcOpResult.getOpResult()).build();
                return dtoOpResult;
        }

        @Override
        public OpResultDto removeBatch(@Valid UuidListDto dtoUuidList) {
                // gRPC 请求的参数使用 Builder 装配模式
                UuidListGrpc.Builder grpcUuidListBuilder = UuidListGrpc.newBuilder();
                for (UuidDto dtoUuid : dtoUuidList.getDtoList()) {
                        UuidGrpc grpcUuid = UuidGrpc.newBuilder()
                                        .setUuid(dtoUuid.getUuid())
                                        .build();
                        grpcUuidListBuilder.addGrpc(grpcUuid);
                }
                UuidListGrpc grpcUuidList = grpcUuidListBuilder.build();
                // 此处是远程 gRPC 调用
                OpResultGrpc grpcOpResult = helloServiceStub.removeBatch(grpcUuidList);
                OpResultDto dtoOpResult = OpResultDto.builder().opResult(grpcOpResult.getOpResult()).build();
                return dtoOpResult;
        }

        @Override
        public OpResultDto deleteOne(@Valid IdExtDto dtoIdExt) {
                // gRPC 请求的参数使用 Builder 装配模式
                IdExtGrpc grpcIdExt = IdExtGrpc.newBuilder()
                                .setIdExt(dtoIdExt.getIdExt())
                                .build();
                // 此处是远程 gRPC 调用
                OpResultGrpc grpcOpResult = helloServiceStub.deleteOne(grpcIdExt);
                OpResultDto dtoOpResult = OpResultDto.builder().opResult(grpcOpResult.getOpResult()).build();
                return dtoOpResult;
        }

        @Override
        public OpResultDto deleteBatch(@Valid IdExtListDto dtoIdExtList) {
                // gRPC 请求的参数使用 Builder 装配模式
                IdExtListGrpc.Builder grpcIdExtListBuilder = IdExtListGrpc.newBuilder();
                for (IdExtDto dtoIdExt : dtoIdExtList.getDtoList()) {
                        IdExtGrpc grpcIdExt = IdExtGrpc.newBuilder()
                                        .setIdExt(dtoIdExt.getIdExt())
                                        .build();
                        grpcIdExtListBuilder.addGrpc(grpcIdExt);
                }
                IdExtListGrpc grpcIdExtList = grpcIdExtListBuilder.build();
                // 此处是远程 gRPC 调用
                OpResultGrpc grpcOpResult = helloServiceStub.deleteBatch(grpcIdExtList);
                OpResultDto dtoOpResult = OpResultDto.builder().opResult(grpcOpResult.getOpResult()).build();
                return dtoOpResult;
        }

        @Override
        public OpResultDto reviveOne(@Valid IdExtDto dtoIdExt) {
                // gRPC 请求的参数使用 Builder 装配模式
                IdExtGrpc grpcIdExt = IdExtGrpc.newBuilder()
                                .setIdExt(dtoIdExt.getIdExt())
                                .build();
                // 此处是远程 gRPC 调用
                OpResultGrpc grpcOpResult = helloServiceStub.reviveOne(grpcIdExt);
                OpResultDto dtoOpResult = OpResultDto.builder().opResult(grpcOpResult.getOpResult()).build();
                return dtoOpResult;
        }

        @Override
        public OpResultDto reviveBatch(@Valid IdExtListDto dtoIdExtList) {
                // gRPC 请求的参数使用 Builder 装配模式
                IdExtListGrpc.Builder grpcIdExtListBuilder = IdExtListGrpc.newBuilder();
                for (IdExtDto dtoIdExt : dtoIdExtList.getDtoList()) {
                        IdExtGrpc grpcIdExt = IdExtGrpc.newBuilder()
                                        .setIdExt(dtoIdExt.getIdExt())
                                        .build();
                        grpcIdExtListBuilder.addGrpc(grpcIdExt);
                }
                IdExtListGrpc grpcIdExtList = grpcIdExtListBuilder.build();
                // 此处是远程 gRPC 调用
                OpResultGrpc grpcOpResult = helloServiceStub.reviveBatch(grpcIdExtList);
                OpResultDto dtoOpResult = OpResultDto.builder().opResult(grpcOpResult.getOpResult()).build();
                return dtoOpResult;
        }

        @Override
        public OpResultDto editSelective(@Valid UserBaseP1K1Dto dtoP1K1) {
                // 将 DTO 对象转换为 gRPC 对象
                UserBaseGrpcP1K1 grpcP1K1 = modelMapper.map(dtoP1K1, UserBaseGrpcP1K1.Builder.class).build();
                // 此处是远程 gRPC 调用
                OpResultGrpc grpcOpResult = helloServiceStub.editSelective(grpcP1K1);
                OpResultDto dtoOpResult = OpResultDto.builder().opResult(grpcOpResult.getOpResult()).build();
                return dtoOpResult;
        }

        @Override
        public OpResultDto updateSelective(@Valid UserBaseP1K2Dto dtoP1K2) {
                // 将 DTO 对象转换为 gRPC 对象
                UserBaseGrpcP1K2 grpcP1K2 = modelMapper.map(dtoP1K2, UserBaseGrpcP1K2.Builder.class).build();
                // 此处是远程 gRPC 调用
                OpResultGrpc grpcOpResult = helloServiceStub.updateSelective(grpcP1K2);
                OpResultDto dtoOpResult = OpResultDto.builder().opResult(grpcOpResult.getOpResult()).build();
                return dtoOpResult;
        }

        @Override
        public CountResultDto getCount() {
                // 此处是远程 gRPC 调用
                CountResultGrpc grpcCountResult = helloServiceStub.getCount(null);
                CountResultDto dtoCountResult = CountResultDto.builder().countResult(grpcCountResult.getCountResult())
                                .build();
                return dtoCountResult;
        }

        @Override
        public UserBaseR1K1Dto getOne(@Valid UuidDto dtoUuid) {
                // gRPC 请求的参数使用 Builder 装配模式
                UuidGrpc grpcUuid = UuidGrpc.newBuilder()
                                .setUuid(dtoUuid.getUuid())
                                .build();
                // 此处是远程 gRPC 调用
                UserBaseGrpcR1K1 grpcR1K1 = helloServiceStub.getOne(grpcUuid);
                // 将 gRPC 对象转换为 DTO 对象
                UserBaseR1K1Dto dtoR1K1 = modelMapper.map(grpcR1K1, UserBaseR1K1Dto.class);
                return dtoR1K1;
        }

        @Override
        public UserBaseR1K1ListDto getBatch(@Valid UuidListDto dtoUuidList) {
                // gRPC 请求的参数使用 Builder 装配模式
                UuidListGrpc.Builder grpcUuidListBuilder = UuidListGrpc.newBuilder();
                for (UuidDto dtoUuid : dtoUuidList.getDtoList()) {
                        UuidGrpc grpcUuid = UuidGrpc.newBuilder()
                                        .setUuid(dtoUuid.getUuid())
                                        .build();
                        grpcUuidListBuilder.addGrpc(grpcUuid);
                }
                UuidListGrpc grpcUuidList = grpcUuidListBuilder.build();
                // 此处是远程 gRPC 调用
                UserBaseGrpcR1K1List grpcR1K1List = helloServiceStub.getBatch(grpcUuidList);
                // 从返回的 gRPC 对象列表构造 DTO 列表
                UserBaseR1K1ListDto dtoR1K1List = UserBaseR1K1ListDto.builder()
                                .dtoList(new ArrayList<UserBaseR1K1Dto>(grpcR1K1List.getGrpcCount()))
                                .build();
                for (UserBaseGrpcR1K1 grpcR1K1 : grpcR1K1List.getGrpcList()) {
                        // 将 gRPC 对象转换为 DTO 对象
                        UserBaseR1K1Dto dtoR1K1 = modelMapper.map(grpcR1K1, UserBaseR1K1Dto.class);
                        dtoR1K1List.getDtoList().add(dtoR1K1);
                }
                return dtoR1K1List;
        }

        @Override
        public UserBaseR1K1ListDto getByPage(@Valid PageRequestDto dtoPageRequest) {
                // gRPC 请求的参数使用 Builder 装配模式
                PageRequestGrpc.Builder grpcPageRequestBuilder = PageRequestGrpc.newBuilder()
                                .setPage(dtoPageRequest.getPage())
                                .setLimit(dtoPageRequest.getLimit());
                // 此处是远程 gRPC 调用
                UserBaseGrpcR1K1List grpcR1K1List = helloServiceStub.getByPage(grpcPageRequestBuilder.build());
                // 从返回的 gRPC 对象列表构造 DTO 列表
                UserBaseR1K1ListDto dtoR1K1List = UserBaseR1K1ListDto.builder()
                                .dtoList(new ArrayList<UserBaseR1K1Dto>(grpcR1K1List.getGrpcCount()))
                                .build();
                for (UserBaseGrpcR1K1 grpcR1K1 : grpcR1K1List.getGrpcList()) {
                        // 将 gRPC 对象转换为 DTO 对象
                        UserBaseR1K1Dto dtoR1K1 = modelMapper.map(grpcR1K1, UserBaseR1K1Dto.class);
                        dtoR1K1List.getDtoList().add(dtoR1K1);
                }
                return dtoR1K1List;
        }

        @Override
        public UuidListDto getUuidByPage(@Valid PageRequestDto dtoPageRequest) {
                // gRPC 请求的参数使用 Builder 装配模式
                PageRequestGrpc.Builder grpcPageRequestBuilder = PageRequestGrpc.newBuilder()
                                .setPage(dtoPageRequest.getPage())
                                .setLimit(dtoPageRequest.getLimit());
                // 此处是远程 gRPC 调用
                UuidListGrpc grpcUuidList = helloServiceStub.getUuidByPage(grpcPageRequestBuilder.build());
                // 从返回的 gRPC 对象列表构造 DTO 列表
                UuidListDto dtoUuidList = UuidListDto.builder()
                                .dtoList(new ArrayList<UuidDto>(grpcUuidList.getGrpcCount()))
                                .build();
                for (UuidGrpc grpcUuid : grpcUuidList.getGrpcList()) {
                        // 将 gRPC 对象转换为 DTO 对象
                        UuidDto dtoUuid = modelMapper.map(grpcUuid, UuidDto.class);
                        dtoUuidList.getDtoList().add(dtoUuid);
                }
                return dtoUuidList;
        }

        @Override
        public CountResultDto selectCount() {
                // 此处是远程 gRPC 调用
                CountResultGrpc grpcCountResult = helloServiceStub.selectCount(null);
                CountResultDto dtoCountResult = CountResultDto.builder().countResult(grpcCountResult.getCountResult())
                                .build();
                return dtoCountResult;
        }

        @Override
        public CountResultDto selectCountRemoved() {
                // 此处是远程 gRPC 调用
                CountResultGrpc grpcCountResult = helloServiceStub.selectCountRemoved(null);
                CountResultDto dtoCountResult = CountResultDto.builder().countResult(grpcCountResult.getCountResult())
                                .build();
                return dtoCountResult;
        }

        @Override
        public UserBaseR1K2Dto selectOne(@Valid IdExtDto dtoIdExt) {
                // gRPC 请求的参数使用 Builder 装配模式
                IdExtGrpc grpcIdExt = IdExtGrpc.newBuilder()
                                .setIdExt(dtoIdExt.getIdExt())
                                .build();
                // 此处是远程 gRPC 调用
                UserBaseGrpcR1K2 grpcR1K2 = helloServiceStub.selectOne(grpcIdExt);
                // 将 gRPC 对象转换为 DTO 对象
                UserBaseR1K2Dto dtoR1K2 = modelMapper.map(grpcR1K2, UserBaseR1K2Dto.class);
                return dtoR1K2;
        }

        @Override
        public UserBaseR1K2ListDto selectBatch(@Valid IdExtListDto dtoIdExtList) {
                // gRPC 请求的参数使用 Builder 装配模式
                IdExtListGrpc.Builder grpcIdExtListBuilder = IdExtListGrpc.newBuilder();
                for (IdExtDto dtoIdExt : dtoIdExtList.getDtoList()) {
                        IdExtGrpc grpcIdExt = IdExtGrpc.newBuilder()
                                        .setIdExt(dtoIdExt.getIdExt())
                                        .build();
                        grpcIdExtListBuilder.addGrpc(grpcIdExt);
                }
                IdExtListGrpc grpcIdExtList = grpcIdExtListBuilder.build();
                // 此处是远程 gRPC 调用
                UserBaseGrpcR1K2List grpcR1K2List = helloServiceStub.selectBatch(grpcIdExtList);
                // 从返回的 gRPC 对象列表构造 DTO 列表
                UserBaseR1K2ListDto dtoR1K2List = UserBaseR1K2ListDto.builder()
                                .dtoList(new ArrayList<UserBaseR1K2Dto>(grpcR1K2List.getGrpcCount()))
                                .build();
                for (UserBaseGrpcR1K2 grpcR1K2 : grpcR1K2List.getGrpcList()) {
                        // 将 gRPC 对象转换为 DTO 对象
                        UserBaseR1K2Dto dtoR1K2 = modelMapper.map(grpcR1K2, UserBaseR1K2Dto.class);
                        dtoR1K2List.getDtoList().add(dtoR1K2);
                }
                return dtoR1K2List;
        }

        @Override
        public UserBaseR1K2ListDto selectByPage(@Valid PageRequestDto dtoPageRequest) {
                // gRPC 请求的参数使用 Builder 装配模式
                PageRequestGrpc.Builder grpcPageRequestBuilder = PageRequestGrpc.newBuilder()
                                .setPage(dtoPageRequest.getPage())
                                .setLimit(dtoPageRequest.getLimit());
                // 此处是远程 gRPC 调用
                UserBaseGrpcR1K2List grpcR1K2List = helloServiceStub.selectByPage(grpcPageRequestBuilder.build());
                // 从返回的 gRPC 对象列表构造 DTO 列表
                UserBaseR1K2ListDto dtoR1K2List = UserBaseR1K2ListDto.builder()
                                .dtoList(new ArrayList<UserBaseR1K2Dto>(grpcR1K2List.getGrpcCount()))
                                .build();
                for (UserBaseGrpcR1K2 grpcR1K2 : grpcR1K2List.getGrpcList()) {
                        // 将 gRPC 对象转换为 DTO 对象
                        UserBaseR1K2Dto dtoR1K2 = modelMapper.map(grpcR1K2, UserBaseR1K2Dto.class);
                        dtoR1K2List.getDtoList().add(dtoR1K2);
                }
                return dtoR1K2List;
        }

        @Override
        public IdExtListDto selectIdExtByPage(@Valid PageRequestDto dtoPageRequest) {
                // gRPC 请求的参数使用 Builder 装配模式
                PageRequestGrpc.Builder grpcPageRequestBuilder = PageRequestGrpc.newBuilder()
                                .setPage(dtoPageRequest.getPage())
                                .setLimit(dtoPageRequest.getLimit());
                // 此处是远程 gRPC 调用
                IdExtListGrpc grpcIdExtList = helloServiceStub.selectIdExtByPage(grpcPageRequestBuilder.build());
                // 从返回的 gRPC 对象列表构造 DTO 列表
                IdExtListDto dtoIdExtList = IdExtListDto.builder()
                                .dtoList(new ArrayList<IdExtDto>(grpcIdExtList.getGrpcCount()))
                                .build();
                for (IdExtGrpc grpcIdExt : grpcIdExtList.getGrpcList()) {
                        // 将 gRPC 对象转换为 DTO 对象
                        IdExtDto dtoIdExt = modelMapper.map(grpcIdExt, IdExtDto.class);
                        dtoIdExtList.getDtoList().add(dtoIdExt);
                }
                return dtoIdExtList;
        }

        @Override
        public IdExtListDto selectIdExtRemoved() {
                // 此处是远程 gRPC 调用
                IdExtListGrpc grpcIdExtList = helloServiceStub.selectIdExtRemoved(null);
                // 从返回的 gRPC 对象列表构造 DTO 列表
                IdExtListDto dtoIdExtList = IdExtListDto.builder()
                                .dtoList(new ArrayList<IdExtDto>(grpcIdExtList.getGrpcCount()))
                                .build();
                for (IdExtGrpc grpcIdExt : grpcIdExtList.getGrpcList()) {
                        // 将 gRPC 对象转换为 DTO 对象
                        IdExtDto dtoIdExt = modelMapper.map(grpcIdExt, IdExtDto.class);
                        dtoIdExtList.getDtoList().add(dtoIdExt);
                }
                return dtoIdExtList;
        }

}